#!/bin/sh
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Name: sfeed_mastodon
# Desc: Post feed data from sfeed to the fediverse.
# Reqs: curl, xargs
# Date: 2023-11-16
# Lisc: GPLv3
# Auth: @jadedctrl@jam.xwx.moe
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

# Print a friendly usage message.
usage() {
	echo "usage: $(basename $0) [-h] [-a FEDI_AUTH] SERVER_URL"
	echo "Posts sfeed(1) feed data from stdin to Mastodon-compatible servers."
	echo ""
	echo "  -h             print this message and exit"
	echo "  -a             the authorization token for your account"
	echo "  -s             the scope for posts, one of: public/unlisted/private/direct"
	echo "  -t             template for post contents"
	echo ""
	echo "To find your authorization token, you can snoop through request headers in"
	echo "your web-browser. In Firefox, this can be done through:"
	echo '    Developer Tools (F12) → Network → Headers'
	echo 'Look for your $FEDI_AUTH value in the Authorization header like so:'
	echo '    Authorization: Bearer $FEDI_AUTH'
	echo 'Either place this value in your $FEDI_AUTH environment variable, or pass it'
	echo "with -a."
	echo ""
	echo "The template (-t) is an HTML value for this script’s post format."
	echo "Post-related variables go within {{double-braces}}, and the following"
	echo "variables are recognized: title, url, desc, desc_short, unix_date."
	echo "By default, the template used is:"
	echo "    <b>{{title}}</b><br>{{url}}<br><br><blockquote>{{desc_short}}</blockquote>"
}


# Deescape a URL-escaped string (percent-encoded), passed over stdin.
url_deescape() {
	sed 's@+@ @g;s@%@\\x@g' \
		| xargs -0 printf "%b"
}


# Takes a post’s contents and create the corresponding client-API JSON.
post_json() {
	local message_text="$1"
	printf '{ "content_type": "text/html", "visibility": "%s",' "$FEDI_SCOPE"
	printf '"status": "%s" }\n' "$message_text"
}


# Post a status with HTML content to the given Mastodon-compatible server.
post_status() {
	local server="$1"
	local auth_token="$2"
	local message_text="$3"

	curl --request POST \
		 --header "Authorization: Bearer $auth_token" \
		 --header "Content-Type: application/json" \
		 --data "$(post_json "$message_text" | tr -d '\n')" \
		 "${server}/api/v1/statuses"
}


# Print an sfeed post line as per $TEMPLATE, with the following variables:
# {{title}}, {{unix_date}}, {{url}}, {{desc}}, {{desc_short}}
sfeed_post_text() {
	local sfeed_line="$1"
	local unix_date="$(echo "$line" | awk --field-separator '\t' '{print $1}')"
	local title="$(echo "$line" | awk --field-separator '\t' '{print $2}')"
	local url="$(echo "$line" | awk --field-separator '\t' '{print $3}' | url_deescape)"
	local desc="$(echo "$line" | awk --field-separator '\t' '{print $4}')"
	local desc_short="$(echo "$desc" | head -c250)"

	# Show that the description was truncated.
	if test "$(echo "$desc_short" | wc -c)" -gt 250; then
		desc_short="$desc_short […]"
	fi

	if test -z "$title"; then
		title="$url"
	fi

	# If there is nothing to post, then don’t stdout anything.
	if test -z "$url"; then
		return
	fi

	printf "$TEMPLATE" \
		| tr -d '|' \
		| sed "s|{{title}}|$title|g" \
		| sed "s|{{unix_date}}|$unix_date|g" \
		| sed "s|{{url}}|$url|g" \
		| sed "s|{{desc}}|$desc|g" \
		| sed "s|{{desc_short}}|$desc_short|g" \
		| sed 's|\\n||g' \
		| sed 's|"|\\"|g' \
		| tr -d '	\n'
}


# Post an sfeed feed entry, by line, to a Mastodon-compatible fedi server.
post_sfeed_line() {
	local server="$1"
	local auth="$2"
	local line="$3"
	local message_text="$(sfeed_post_text "$line")"

	if test -n "$line" -a -n "$message_text"; then
		post_status "$server" "$auth" "$message_text"
	fi
}


TEMPLATE='<b>{{title}}</b><br>{{url}}<br><br><blockquote>{{desc_short}}</blockquote>'
while getopts 'ha:t:' arg; do
	case $arg in
		h)
			usage
			exit 0
			;;
		s)
			FEDI_SCOPE="$OPTARG"
			;;
		a)
			FEDI_AUTH="$OPTARG"
			;;
		t)
			TEMPLATE="$OPTARG"
			;;
	esac
done

shift $((OPTIND-1))
SERVER_URL="$1"


if test -z "$FEDI_AUTH"; then
	1>&2 echo 'You need to set the environment variable $FEDI_AUTH!'
	1>&2 echo 'You can find your auth key by examining the "Authentication: Bearer" header'
	1>&2 echo "used in requests by your server's web-client."
    1>&2 echo 'In Firefox, F12→Network.'
	1>&2 echo ""
	exit 2
fi

if test -z "$SERVER_URL"; then
	1>&2 echo "No server specified!"
	1>&2 echo "Make sure to provide a server base URL (like https://fedi.server) as the last argument."
	1>&2 echo ""
	1>&2 usage
	exit 3
fi


if test -z "$FEDI_SCOPE"; then
	FEDI_SCOPE="public"
fi


IFS="
"
while read -r line; do
	post_sfeed_line "$SERVER_URL" "$FEDI_AUTH" "$line"
done
